package org.zjx.core;

import lombok.SneakyThrows;
import org.zjx.message.CommandMessage;
import org.zjx.message.Message;
import org.zjx.message.ResponseMessage;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.TimeUnit;

/**
 * 基于连接池的Socket远程调用器
 *
 * 改进点：
 * 1. 复用TCP连接提升性能
 * 2. 自动管理连接生命周期
 * 3. 集成心跳检测机制
 */
public class SocketRemoteInvoker implements RemoteCommandInvoker {
    private final SocketPool socketPool;  // 连接池实例

    /**
     * 构造函数（从配置初始化）
     * @param config 包含连接池配置的Socket配置
     */
    public SocketRemoteInvoker(SocketConfig config) {
        this.socketPool = new SocketPool(
                config.getPoolMaxTotal(),
                config.getPoolMaxIdleTime(),
                TimeUnit.MILLISECONDS
        );
    }

    /**
     * 执行远程命令调用
     */
    @Override
    @SneakyThrows
    public ResponseMessage invokeRemote(CommandMessage command, InetSocketAddress target){
        SocketPool.PooledSocket pooledSocket = null;
        try {
            // 1. 从连接池获取连接
            pooledSocket = socketPool.borrowSocket(target);
            pooledSocket.touch();  // 更新最后使用时间

            // 2. 获取底层Socket通道
            Socket socket = pooledSocket.getSocket();
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            // 3. 发送命令（JSON格式）
            out.println(command.toJsonString());

            // 4. 接收响应（带超时控制）
            String response = in.readLine();
            if (response == null) {
                throw new IOException("远程服务未响应");
            }

            // 5. 解析响应消息
            Message message = Message.parse(response);
            if (!(message instanceof ResponseMessage)) {
                throw new IOException("无效响应类型: " + message.getType());
            }

            return (ResponseMessage) message;
        } finally {
            // 6. 归还连接到连接池
            if (pooledSocket != null) {
                socketPool.returnSocket(pooledSocket);
            }
        }
    }

    /**
     * 关闭连接池（服务停止时调用）
     */
    public void close() {
        socketPool.cleanup();
    }
}